package mobi.smarthosts;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;

public class ShellExecutor {

    private static Process getProcess() {
        try {
            return Runtime.getRuntime().exec(new String[]{"su", "-c", "system/bin/sh"});
        } catch (IOException e) {
            String msg = "Execute command as su failed.";
            Log.w(msg, e);
              return null;
        }
    }

    public static boolean mountSystemFolder() {
        String res = executeRootCommand("mount -o rw,remount /system");
        return (Utils.isEmptyString(res));
    }

    public static boolean unmountSystemFolder() {
        String res = executeRootCommand("mount -o ro,remount /system");
        return (Utils.isEmptyString(res));
    }

    public static boolean isRootedDevice() {
        String su = "su";
        String[] places = { "/sbin/", "/system/bin/", "/system/xbin/",
                "/data/local/xbin/", "/data/local/bin/", "/system/sd/xbin/", "/system/bin/failsafe/", "/data/local/" };
        for (String where : places) {
            File file = new File(where + su);
            if (file.exists()) {
                Log.i("su was found here: " + where);
                return true;
            }
        }
        return false;
    }

    public static void rootCopyFile(File sourceFile, File destination) {
        String cmd = "cp -Rp " + sourceFile + " " + destination;
        executeRootCommand(cmd, "chmod 666 "+destination);
    }

    public static String executeRootCommand(String... commands) {
        try {
            Process p = getProcess();
            DataOutputStream stdin = new DataOutputStream(p.getOutputStream());
            BufferedReader stdoutReader = new BufferedReader(new InputStreamReader(p.getInputStream()));

            for (String cmd : commands) {
                Log.d("Run su command: " + cmd);
                stdin.writeBytes(cmd+"\n");
            }
            stdin.writeBytes("exit\n");
            stdin.flush();

            StringBuilder sb = new StringBuilder();
            String line = null;
            while ((line = stdoutReader.readLine()) != null)
                sb.append(line).append("\n");

            p.waitFor();
            p.destroy();
            stdin.close();
            stdoutReader.close();

            Log.d("Run su command result: %s", sb.toString());
            return sb.toString();

            // Another workable version. Will require permission for many times.
/*
            Process p = new ProcessBuilder()
                .command("su", "-c", command)
                .redirectErrorStream(true)
                .start();

            // Read std input
            BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
            StringBuilder sb = new StringBuilder();
            String line = null;
            while ((line = reader.readLine()) != null)
                sb.append(line).append("\n");

            // Close the terminal
            p.waitFor();
            p.destroy();

            Log.d("Run su command result: %s", sb.toString());
            return sb.toString();
*/
        } catch (InterruptedException e) {
            String msg = "Process is terminated unexpectedly.";
            Log.e(msg);
            throw new SmartHostsException(msg, e);
        } catch (IOException e) {
            String msg = "Execute command as su failed.";
            Log.w(msg, e);
            return null;
        }
    }

    public static String rootReadFile(String path) {
        try {
            Process p = getProcess();
            DataOutputStream stdin = new DataOutputStream(p.getOutputStream());
            BufferedReader stdoutReader = new BufferedReader(new InputStreamReader(p.getInputStream()));

            Log.d("Root read file: %s", path);
            stdin.writeBytes("cat "+path+"\n");
            stdin.writeBytes("exit\n");
            stdin.flush();

            StringBuilder sb = new StringBuilder();
            String line = null;
            while ((line = stdoutReader.readLine()) != null)
                sb.append(line).append("\n");

            p.waitFor();
            p.destroy();
            stdin.close();
            stdoutReader.close();

            // Check if file is existed.
            if (sb.toString().contains("No such file or directory")) {
                Log.d("File %s is not existed.", path);
                return null;
            }

            Log.d("Root read done with %s bytes.", sb.length());
            return sb.toString();

        } catch (InterruptedException e) {
            String msg = "Process is terminated unexpectedly.";
            Log.e(msg);
            throw new SmartHostsException(msg, e);
        } catch (IOException e) {
            String msg = "Root read file failed.";
            Log.w(msg, e);
            return null;
        }
    }

    public static void rootWriteFile(String path, String content, boolean append) {
        try {
            Process p = getProcess();
            DataOutputStream stdin = new DataOutputStream(p.getOutputStream());
            BufferedReader stdoutReader = new BufferedReader(new InputStreamReader(p.getInputStream()));

            Log.d("Root write file: %s", path);
            String[] lines = content.split("\n");
            for (int i=0; i<lines.length; i++)
                stdin.writeBytes("echo \""+lines[i]+"\" "+(((i == 0) && !append) ?">":">>")+" "+path+"\n");
            stdin.writeBytes("ls -l "+path+"\n");
            stdin.writeBytes("exit\n");
            stdin.flush();

            StringBuilder sb = new StringBuilder();
            String line = null;
            while ((line = stdoutReader.readLine()) != null)
                sb.append(line).append("\n");

            p.waitFor();
            p.destroy();
            stdin.close();
            stdoutReader.close();

            Log.d("Root write done. %s", sb.toString());

        } catch (InterruptedException e) {
            String msg = "Process is terminated unexpectedly.";
            Log.e(msg);
            throw new SmartHostsException(msg, e);
        } catch (IOException e) {
            String msg = "Root write file failed.";
            Log.w(msg, e);
        }
    }

    public static void rootAppendFile(String path1, String path2) {
        try {
            Process p = getProcess();
            DataOutputStream stdin = new DataOutputStream(p.getOutputStream());
            BufferedReader stdoutReader = new BufferedReader(new InputStreamReader(p.getInputStream()));

            Log.d("Root append file: %s to %s", path2, path1);
            stdin.writeBytes("echo | cat - "+path2+" >> "+path1+"\n");
            stdin.writeBytes("exit\n");
            stdin.flush();

            StringBuilder sb = new StringBuilder();
            String line = null;
            while ((line = stdoutReader.readLine()) != null)
                sb.append(line).append("\n");

            p.waitFor();
            p.destroy();
            stdin.close();
            stdoutReader.close();

            Log.d("Root write done. %s", sb.toString());

        } catch (InterruptedException e) {
            String msg = "Process is terminated unexpectedly.";
            Log.e(msg);
            throw new SmartHostsException(msg, e);
        } catch (IOException e) {
            String msg = "Root write file failed.";
            Log.w(msg, e);
        }
    }

}
